﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;

namespace KABS_Commander
{
    // State object for reading client data asynchronously
    public class StateObject
    {
        // Client  socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 128;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
    }

    public partial class KABS_Commander : Form
    {
        private Socket socket_comm = new Socket(SocketType.Stream, ProtocolType.Tcp);

        private void InitializeIPInfo()
        {
            string hostName = Dns.GetHostName();
            IPAddress[] ips = Dns.GetHostAddresses(hostName);
            IPAddress ipv4 = ips[1];
            string ip = ipv4.ToString();

            textBox_localIP.Text = ip;
            textBox_remoteIP.Text = ip;
        }

        private void setTCPSettingEnable()
        {
            bool b = !socket_comm.Connected;

            textBox_remoteIP.Enabled = b;
            textBox_port.Enabled = b;
            SetInputEnable(); 
        }

        private void button_connectRemote_Click(object sender, EventArgs e)
        {
            if (!socket_comm.Connected)
            {
                socket_comm = new Socket(SocketType.Stream, ProtocolType.Tcp);
                string remoteIP = textBox_remoteIP.Text;
                IPAddress ip = new IPAddress(0);
                int port = 0;
                try
                {
                    ip = IPAddress.Parse(remoteIP);
                    port = int.Parse(textBox_port.Text);
                }
                catch (Exception ee)
                {
                    MessageBox.Show("Invalid IP or port number!");
                    return;
                }
                try
                {
                    socket_comm.Connect(ip, port);

                    StateObject so = new StateObject();
                    so.workSocket = socket_comm;
                    socket_comm.BeginReceive(so.buffer, 0, StateObject.BufferSize, 0,
                                             new AsyncCallback(receiveCallback), so);
                }
                catch (Exception ee)
                {
                    MessageBox.Show("Connect failed!");
                        return;
                }
                if (socket_comm.Connected)
                {
                    button_connectRemote.Text = "Disconnect";
                }
            }
            else
            {
                socket_comm.Shutdown(SocketShutdown.Both);
                socket_comm.Close();
                button_connectRemote.Text = "Connect";
            }
            setTCPSettingEnable();
        }

        private void receiveCallback(IAsyncResult ar)
        {
            String content = String.Empty;

            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket s = state.workSocket;

            try
            {
                // Read data from the client socket. 
                int bytesRead = s.EndReceive(ar);

                if (bytesRead > 0)
                {
                    // There  might be more data, so store the data received so far.
                    state.sb.Append(Encoding.ASCII.GetString(
                        state.buffer, 0, bytesRead));

                    // Check for end-of-file tag. If it is not there, read 
                    // more data.
                    content = state.sb.ToString();
                    appendText(content);
                    state.sb.Clear();
                }

                s.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                                        new AsyncCallback(receiveCallback), state);
            }
            catch (Exception ee)
            {
                setSocketState();
            }
        }

        // Serial data received
        delegate void SocketStateCallback();
        private void setSocketState()
        {
            // InvokeRequired required compares the thread ID of the 
            // calling thread to the thread ID of the creating thread. 
            // If these threads are different, it returns true. 
            if (this.button_connectRemote.InvokeRequired)
            {
                SocketStateCallback d = new SocketStateCallback(setSocketState);
                this.Invoke(d, new object[] {});
            }
            else
            {
                button_connectRemote.Text = "Connect";
            }
        }
    }
}